package com.ly.dingtalk.service.message.impl;


import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.jetbrains.annotations.NotNull;

import com.aliyun.dingtalkim_1_0.Client;
import com.aliyun.dingtalkim_1_0.models.SendInteractiveCardHeaders;
import com.aliyun.dingtalkim_1_0.models.SendInteractiveCardRequest;
import com.aliyun.dingtalkim_1_0.models.SendInteractiveCardResponse;
import com.aliyun.dingtalkim_1_0.models.UpdateInteractiveCardHeaders;
import com.aliyun.dingtalkim_1_0.models.UpdateInteractiveCardRequest;
import com.aliyun.dingtalkrobot_1_0.models.BatchOTOQueryHeaders;
import com.aliyun.dingtalkrobot_1_0.models.BatchOTOQueryRequest;
import com.aliyun.dingtalkrobot_1_0.models.BatchOTOQueryResponse;
import com.aliyun.dingtalkrobot_1_0.models.BatchRecallOTOHeaders;
import com.aliyun.dingtalkrobot_1_0.models.BatchRecallOTORequest;
import com.aliyun.dingtalkrobot_1_0.models.BatchRecallOTOResponse;
import com.aliyun.dingtalkrobot_1_0.models.BatchSendOTOHeaders;
import com.aliyun.dingtalkrobot_1_0.models.BatchSendOTORequest;
import com.aliyun.dingtalkrobot_1_0.models.BatchSendOTOResponse;
import com.aliyun.dingtalkrobot_1_0.models.OrgGroupQueryHeaders;
import com.aliyun.dingtalkrobot_1_0.models.OrgGroupQueryRequest;
import com.aliyun.dingtalkrobot_1_0.models.OrgGroupQueryResponse;
import com.aliyun.dingtalkrobot_1_0.models.OrgGroupRecallHeaders;
import com.aliyun.dingtalkrobot_1_0.models.OrgGroupRecallRequest;
import com.aliyun.dingtalkrobot_1_0.models.OrgGroupRecallResponse;
import com.aliyun.dingtalkrobot_1_0.models.OrgGroupSendRequest;
import com.aliyun.dingtalkrobot_1_0.models.OrgGroupSendResponse;
import com.aliyun.teautil.models.RuntimeOptions;
import com.dingtalk.api.request.OapiRobotSendRequest;
import com.dingtalk.api.response.OapiRobotSendResponse;
import com.ly.dingtalk.common.exception.DingApiException;
import com.ly.dingtalk.component.application.IDingBot;
import com.ly.dingtalk.pojo.message.bot.IDingBotMsg;
import com.ly.dingtalk.pojo.message.interactive.IDingInteractiveMsg;
import com.ly.dingtalk.service.AbstractDingNewApi;
import com.ly.dingtalk.service.IDingInteractiveMessageHandler;
import com.ly.dingtalk.service.message.IDingBotMessageHandler;
import com.ly.dingtalk.service.user.impl.DingUserHandler;

import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;

/**
 * @author wangzhen
 */
@Slf4j
public class DingBotMessageHandler extends AbstractDingNewApi implements IDingBotMessageHandler, IDingInteractiveMessageHandler {

    public DingBotMessageHandler(IDingBot app) {
        super(app);
    }

    /**
     * 
     * @Description: 使用机器人向用户发送单聊
     * @see com.ly.dingtalk.service.message.IDingBotMessageHandler#sendToUserByUserIds(java.util.List, com.ly.dingtalk.pojo.message.bot.IDingBotMsg)
     * @date 2023-12-25 01:46:47
     */
    @Override
    public BatchSendOTOResponse sendToUserByUserIds(@NonNull List<String> userIds, @NonNull IDingBotMsg msg) {
        BatchSendOTOHeaders headers = new BatchSendOTOHeaders();
        headers.xAcsDingtalkAccessToken = accessToken();
        BatchSendOTORequest request = new BatchSendOTORequest()
                .setRobotCode(app.getAppKey())
                .setUserIds(userIds)
                .setMsgKey(msg.getMsgType())
                .setMsgParam(msg.getMsg());
        final BatchSendOTOResponse response = execute(
                com.aliyun.dingtalkrobot_1_0.Client.class,
                client -> {
                    try {
                        return client.batchSendOTOWithOptions(request, headers, new RuntimeOptions());
                    } catch (Exception e) {
                        log.error("机器人向用户发送普通消息失败", e);
                        throw new DingApiException("机器人向用户发送普通消息失败");
                    }
                },
                () -> "机器人向用户发送普通消息");
        log.debug("机器人向用户发送普通消息响应:{}", response);
        return response;
    }
    
    @Override
    public BatchOTOQueryResponse isReadSendMessage(BatchOTOQueryRequest req) {
        return execute(com.aliyun.dingtalkrobot_1_0.Client.class, client->{
            BatchOTOQueryResponse batchOTOQueryWithOptions = null;
            try {
                BatchOTOQueryHeaders batchOTOQueryHeaders = new BatchOTOQueryHeaders();
                batchOTOQueryHeaders.xAcsDingtalkAccessToken = accessToken();
                batchOTOQueryWithOptions = client.batchOTOQueryWithOptions(req, batchOTOQueryHeaders, new RuntimeOptions());
            } catch (Exception e) {
                log.error("isReadSendMessage报错了", e);
                throw new DingApiException(e.getMessage());
            }
            return batchOTOQueryWithOptions;
        }, () -> "机器人发送的单聊信息是否已读");
    }
    
    /**
     * @Description: 撤回机器人发送的单聊信息
     * @see com.ly.dingtalk.service.message.IDingBotMessageHandler#recallSendMessage(com.aliyun.dingtalkrobot_1_0.models.BatchRecallOTORequest)
     * @date 2023-12-25 02:05:05
     */
    @Override
    public BatchRecallOTOResponse recallSendMessage(BatchRecallOTORequest req) {
        return execute(com.aliyun.dingtalkrobot_1_0.Client.class, client ->{
            BatchRecallOTOResponse batchRecallOTOWithOptions = null;
            try {
                BatchRecallOTOHeaders batchRecallOTOHeaders = new BatchRecallOTOHeaders();
                batchRecallOTOHeaders.xAcsDingtalkAccessToken = accessToken();
                batchRecallOTOWithOptions = client.batchRecallOTOWithOptions(req, batchRecallOTOHeaders, new RuntimeOptions());
            } catch (Exception e) {
                log.error("recallSendMessage报错!", e);
                throw new DingApiException(e.getMessage());
            }
            return batchRecallOTOWithOptions;
        }, ()->"撤回机器人发送的单聊信息");
    }

    @Override
    public BatchSendOTOResponse sendToUserByPhones(@NonNull List<String> mobiles, @NonNull IDingBotMsg msg) {
        final DingUserHandler handler = new DingUserHandler(app);
        final List<String> userIds = mobiles
                .stream()
                .map(handler::findUserIdByMobile)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        return sendToUserByUserIds(userIds, msg);
    }

    @Override
    public String sendInteractiveMsgToIndividual(@NotNull List<String> userIds, @NotNull IDingInteractiveMsg interactiveMsg) {
        SendInteractiveCardHeaders sendInteractiveCardHeaders = new SendInteractiveCardHeaders();
        sendInteractiveCardHeaders.xAcsDingtalkAccessToken = accessToken();
        SendInteractiveCardRequest.SendInteractiveCardRequestCardData cardData = new SendInteractiveCardRequest.SendInteractiveCardRequestCardData();
        cardData.setCardParamMap(interactiveMsg.getMsg());
        SendInteractiveCardRequest sendInteractiveCardRequest = new SendInteractiveCardRequest()
                .setCardTemplateId(interactiveMsg.getTemplateId())
                .setReceiverUserIdList(userIds)
                .setConversationType(0)
                .setCallbackRouteKey(interactiveMsg.getCallbackRouteKey())
                .setCardData(cardData)
                .setOutTrackId(interactiveMsg.getOutTrackId());
        final SendInteractiveCardResponse response = execute(
                Client.class,
                client -> {
                    try {
                        return client.sendInteractiveCardWithOptions(sendInteractiveCardRequest, sendInteractiveCardHeaders, new RuntimeOptions());
                    } catch (Exception e) {
                        log.error("机器人发送互动卡片高级版至个人失败", e);
                        throw new DingApiException("机器人发送互动卡片高级版至个人失败");
                    }
                },
                () -> "机器人发送互动卡片高级版至个人"
        );
        final String processQueryKey = response.getBody().getResult().getProcessQueryKey();
        log.debug("机器人发送互动卡片高级版至个人实例id:{}", processQueryKey);
        return interactiveMsg.getOutTrackId();
    }

    @Deprecated
    @Override
    public String sendInteractiveMsgToGroup(List<String> userIds, String openConversationId, IDingInteractiveMsg interactiveMsg) {
        SendInteractiveCardHeaders sendInteractiveCardHeaders = new SendInteractiveCardHeaders();
        sendInteractiveCardHeaders.xAcsDingtalkAccessToken = accessToken();
        SendInteractiveCardRequest.SendInteractiveCardRequestCardData cardData = new SendInteractiveCardRequest.SendInteractiveCardRequestCardData();
        cardData.setCardParamMap(interactiveMsg.getMsg());
        SendInteractiveCardRequest sendInteractiveCardRequest = new SendInteractiveCardRequest()
                .setRobotCode(app.getAppKey())
                .setOpenConversationId(openConversationId)
                .setCardTemplateId(interactiveMsg.getTemplateId())
                .setReceiverUserIdList(userIds)
                .setConversationType(1)
                .setCallbackRouteKey(interactiveMsg.getCallbackRouteKey())
                .setCardData(cardData)
                .setOutTrackId(interactiveMsg.getOutTrackId());

        final SendInteractiveCardResponse response = execute(
                Client.class,
                client -> {
                    try {
                        return client.sendInteractiveCardWithOptions(sendInteractiveCardRequest, sendInteractiveCardHeaders, new RuntimeOptions());
                    } catch (Exception e) {
                        log.error("机器人发送互动卡片高级版至群聊失败");
                        throw new DingApiException("机器人发送互动卡片高级版至群聊失败");
                    }
                },
                () -> "机器人发送互动卡片高级版至群聊"
        );
        final String processQueryKey = response.getBody().getResult().getProcessQueryKey();
        log.debug("机器人发送互动卡片高级版至群聊实例id:{}", processQueryKey);
        return interactiveMsg.getOutTrackId();
    }

    @Override
    public String updateInteractiveMsg(@NotNull String openConversationId, @NotNull IDingInteractiveMsg interactiveMsg) {
        UpdateInteractiveCardHeaders updateInteractiveCardHeaders = new UpdateInteractiveCardHeaders();
        updateInteractiveCardHeaders.xAcsDingtalkAccessToken = accessToken();
        UpdateInteractiveCardRequest.UpdateInteractiveCardRequestCardOptions cardOptions = new UpdateInteractiveCardRequest.UpdateInteractiveCardRequestCardOptions()
                .setUpdateCardDataByKey(true)
                .setUpdatePrivateDataByKey(true);
        UpdateInteractiveCardRequest.UpdateInteractiveCardRequestCardData cardData = new UpdateInteractiveCardRequest.UpdateInteractiveCardRequestCardData()
                .setCardParamMap(interactiveMsg.getMsg());
        UpdateInteractiveCardRequest updateInteractiveCardRequest = new UpdateInteractiveCardRequest()
                .setOutTrackId(interactiveMsg.getOutTrackId())
                .setCardData(cardData).setUserIdType(1)
                .setCardOptions(cardOptions);
        execute(
                Client.class,
                client -> {
                    try {
                        return client.updateInteractiveCardWithOptions(updateInteractiveCardRequest, updateInteractiveCardHeaders, new RuntimeOptions());
                    } catch (Exception e) {
                        log.error("机器人更新互动卡片高级版失败", e);
                        throw new DingApiException("机器人更新互动卡片高级版失败");
                    }
                },
                () -> "机器人更新互动卡片高级版"
        );
        return interactiveMsg.getOutTrackId();
    }

    /**
     * 
     * @Description: 发送群聊,不@任何人
     * @see com.ly.dingtalk.service.message.IDingBotMessageHandler#sendGroupChat(com.aliyun.dingtalkrobot_1_0.models.OrgGroupSendRequest)
     */
    @Override
    public OrgGroupSendResponse sendGroupChat(OrgGroupSendRequest req) {
        return execute(com.aliyun.dingtalkrobot_1_0.Client.class, client->{
            OrgGroupSendResponse orgGroupSendWithOptions = null;
            try {
                com.aliyun.dingtalkrobot_1_0.models.OrgGroupSendHeaders orgGroupSendHeaders = new com.aliyun.dingtalkrobot_1_0.models.OrgGroupSendHeaders();
                orgGroupSendHeaders.xAcsDingtalkAccessToken = accessToken();
                orgGroupSendWithOptions = client.orgGroupSendWithOptions(req, orgGroupSendHeaders, new RuntimeOptions());
            } catch (Exception e) {
                log.error("sendGroupChat报错!", e);
                throw new DingApiException(e.getMessage());
            }
            return orgGroupSendWithOptions;
        }, null);
    }

    /**
     * @Description: 就是查询sendGroupChat 发送的消息哪些人是已读的,返回的已读人的userId
     * @see com.ly.dingtalk.service.message.IDingBotMessageHandler#orgGroupQueryWithOptions(com.aliyun.dingtalkrobot_1_0.models.OrgGroupQueryRequest)
     */
    @Override
    public OrgGroupQueryResponse orgGroupQueryWithOptions(OrgGroupQueryRequest req) {
       return execute(com.aliyun.dingtalkrobot_1_0.Client.class, client->{
            OrgGroupQueryResponse orgGroupQueryWithOptions = null;
            try {
                OrgGroupQueryHeaders orgGroupQueryHeaders = new OrgGroupQueryHeaders();
                orgGroupQueryHeaders.xAcsDingtalkAccessToken = accessToken();
                orgGroupQueryWithOptions = client.orgGroupQueryWithOptions(req, orgGroupQueryHeaders, new RuntimeOptions());
            } catch (Exception e) {
                log.error("orgGroupQueryWithOptions报错!", e);
                throw new DingApiException(e.getMessage());
            }
            return orgGroupQueryWithOptions;
        }, ()->"查询企业机器人群聊消息用户已读状态");
    }

    /**
     * 
     * @Description: 撤回 sendGroupChat 方法发送的消息
     * @see com.ly.dingtalk.service.message.IDingBotMessageHandler#recallGroupChat(com.aliyun.dingtalkrobot_1_0.models.OrgGroupRecallRequest)
     * @date 2023-12-25 01:41:37
     */
    @Override
    public OrgGroupRecallResponse recallGroupChat(OrgGroupRecallRequest req) {
        return execute(com.aliyun.dingtalkrobot_1_0.Client.class, client->{
            OrgGroupRecallResponse orgGroupRecallWithOptions = null;
            try {
                OrgGroupRecallHeaders orgGroupRecallHeaders = new OrgGroupRecallHeaders();
                orgGroupRecallHeaders.xAcsDingtalkAccessToken = accessToken();
                orgGroupRecallWithOptions = client.orgGroupRecallWithOptions(req, orgGroupRecallHeaders, new RuntimeOptions());
            } catch (Exception e) {
                log.error("recallGroupChat报错!",e);
                throw new DingApiException(e.getMessage());
            }
            return orgGroupRecallWithOptions;

        }, ()->"撤回群聊消息");
    }

    @Override
    public OapiRobotSendResponse sendBotCard(String sessionWebhook, OapiRobotSendRequest req) {
        return execute(sessionWebhook, req, ()->"机器人发送各种类型的消息");
    }
}
